/*
 * Copyright (c) 2018 Xilinx Inc.
 * Written by Francisco Iglesias.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include <sstream>
#include <string>
#include <vector>
#include <array>

#define SC_INCLUDE_DYNAMIC_PROCESSES

#include "systemc"
using namespace sc_core;
using namespace sc_dt;
using namespace std;

#include "tlm.h"
#include "tlm_utils/simple_initiator_socket.h"
#include "tlm_utils/simple_target_socket.h"

#include "tlm-modules/tlm-splitter.h"
#include "tlm-bridges/tlm2axis-bridge.h"
#include "tlm-bridges/axis2tlm-bridge.h"
#include "traffic-generators/tg-tlm.h"
#include "traffic-generators/traffic-desc.h"
#include "test-modules/memory.h"
#include "test-modules/signals-axis.h"
#include "test-modules/utils.h"
//#include "test-modules/trace-axis.h"

using namespace utils;

#define SZ_1K 1024

#define AXI_DATA_WIDTH 64

const unsigned char burst_data[] = {
	0x11, 0x12, 0x13, 0x14, 0x21, 0x22, 0x23, 0x24,
	0x21, 0x22, 0x23, 0x24, 0x31, 0x32, 0x33, 0x34,
	0x31, 0x32, 0x33, 0x34, 0x41, 0x42, 0x43, 0x44,
	0x41, 0x42, 0x43, 0x44, 0x51, 0x52, 0x53, 0x54
};

TrafficDesc transfers(merge({
	Write(0x0, DATA(0xaa, 0xbb, 0xcc, 0xdd)),
		GenAttr(0x10, false, true),
	Write(0x0, DATA(0xff, 0xdd, 0xcc, 0xbb)),
	Write(0x0, burst_data, sizeof(burst_data)),
		GenAttr(0x10, false, true)
}));

int sc_main(int argc, char *argv[])
{
	tlm2axis_bridge<AXI_DATA_WIDTH>
		tlm2axis_bridge("tlm2axis_bridge");

	axis2tlm_bridge<AXI_DATA_WIDTH>
		axis2tlm_bridge("axis2tlm_bridge");

	AXISSignals<AXI_DATA_WIDTH>
		signals("axis_signals");

	TLMTrafficGenerator gen("gen", 1);
	sc_clock clk("clk", sc_time(20, SC_US));
	sc_signal<bool> resetn("resetn", true);
	memory mem("mem", sc_time(10, SC_NS), SZ_1K);
	memory ref_mem("ref_mem", sc_time(10, SC_NS), SZ_1K);
	tlm_splitter<2> splitter("splitter", true);

	gen.enableDebug();

	// Connect clk
	tlm2axis_bridge.clk(clk);
	axis2tlm_bridge.clk(clk);

	// Connect reset
	tlm2axis_bridge.resetn(resetn);
	axis2tlm_bridge.resetn(resetn);

	// Connect signals
	signals.connect(tlm2axis_bridge);
	signals.connect(axis2tlm_bridge);

	// Connect tlm sockets
	gen.socket.bind(splitter.target_socket);
	splitter.i_sk[0]->bind(tlm2axis_bridge.tgt_socket);
	axis2tlm_bridge.socket.bind(mem.socket);
	splitter.i_sk[1]->bind(ref_mem.socket);

	gen.addTransfers(transfers, 0);

	sc_trace_file *trace_fp = sc_create_vcd_trace_file(argv[0]);

	sc_trace(trace_fp, clk, clk.name());
	signals.Trace(trace_fp);

	sc_start(100, SC_MS);

	sc_stop();

	if (trace_fp) {
		sc_close_vcd_trace_file(trace_fp);
	}

	return 0;
}
